/*
 * @ : Copyright (c) 2021 Phytium Information Technology, Inc. 
 *  
 * SPDX-License-Identifier: Apache-2.0.
 * 
 * @Date: 2021-09-15 19:45:31
 * @LastEditTime: 2021-09-26 10:10:40
 * @Description:  This files is for 
 * 
 * @Modify History: 
 *  Ver   Who        Date         Changes
 * ----- ------     --------    --------------------------------------
 */
#include "ft_assert.h"
#include "parameters.h"
#include "interrupt.h"
#include "f_sdio.h"
#include "f_sdio_hw.h"

u32 FSdioGetIntrMask(FSdioCtrl *ctrl_p, u32 intr_type)
{
    FT_ASSERTZERONUM(ctrl_p && (FSDIO_MAX_INTR_TYPE > intr_type));
    u32 mask;

    if (FSDIO_GENERAL_INTR == intr_type)
    {
        mask = FSDIO_READ_REG(ctrl_p, FSDIO_REG_INT_MASK_OFFSET);
    }
    else if (FSDIO_IDMA_INTR == intr_type)
    {
        mask = FSDIO_READ_REG(ctrl_p, FSDIO_REG_DMAC_INT_ENA_OFFSET);
    }

    return mask;
}

void FSdioSetIntrMask(FSdioCtrl *ctrl_p, u32 intr_type, u32 set_mask, boolean enable)
{
    FT_ASSERTVOID(ctrl_p && (FSDIO_MAX_INTR_TYPE > intr_type));
    u32 mask = FSdioGetIntrMask(ctrl_p, intr_type);

    if (TRUE == enable)
        mask |= set_mask;
    else
        mask &= (~set_mask);

    if (FSDIO_GENERAL_INTR == intr_type)
    {
        /* value of 0 masks interrupt; 
           value of 1 enables interrupt */
        FSDIO_WRITE_REG(ctrl_p, FSDIO_REG_INT_MASK_OFFSET, mask);
    }
    else if (FSDIO_IDMA_INTR == intr_type)
    {
        /* when set, a interrupt is enable
        */
       FSDIO_WRITE_REG(ctrl_p, FSDIO_REG_DMAC_INT_ENA_OFFSET, mask);
    }

    return;
}

u32 FSdioIntrInit(FSdioCtrl *ctrl_p)
{
    FT_ASSERTZERONUM(ctrl_p);
    u32 reg_val;
    FSdioConfig *config_p = &ctrl_p->config;

    /* disable all interrupt (general intr & idma intr) */
    FSdioSetIntrMask(ctrl_p, FSDIO_GENERAL_INTR, GENMASK(31, 0), FALSE);
    FSdioSetIntrMask(ctrl_p, FSDIO_IDMA_INTR, GENMASK(31, 0), FALSE);

    /* clear interrupt status */
    reg_val = FSDIO_READ_REG(ctrl_p, FSDIO_REG_RAW_INTS_OFFSET);
    FSDIO_WRITE_REG(ctrl_p, FSDIO_REG_RAW_INTS_OFFSET, reg_val);
    reg_val = FSDIO_READ_REG(ctrl_p, FSDIO_REG_DMAC_STATUS_OFFSET);
    FSDIO_WRITE_REG(ctrl_p, FSDIO_REG_DMAC_STATUS_OFFSET, reg_val);

    /* register intr, attach interrupt handler */
    InterruptSetPriority(config_p->irq_num, config_p->irq_priority);
    InterruptInstall(config_p->irq_num, ctrl_p->intr_handler, ctrl_p, config_p->irq_name);       

    /* umask intr */
    if (TRUE == config_p->enable_irq)
        InterruptUmask(config_p->irq_num);
    else
        InterruptMask(config_p->irq_num);

    /* enable card detect interrupt */
    reg_val = FSDIO_INT_CD_BIT | FSDIO_INT_CMD_BIT | FSDIO_INT_DTO_BIT | 
              FSDIO_INT_RCRC_BIT | FSDIO_INT_DCRC_BIT | FSDIO_INT_RTO_BIT |
              FSDIO_INT_DRTO_BIT | FSDIO_INT_HTO_BIT | FSDIO_INT_SBE_BCI_BIT |
              FSDIO_INT_EBE_BIT | FSDIO_INT_RE_BIT | FSDIO_INT_HLE_BIT;

    FSdioSetIntrMask(ctrl_p, FSDIO_GENERAL_INTR, reg_val, TRUE);

    /* enable global intrrupt flag */
    FSDIO_SET_BITS(ctrl_p, FSDIO_REG_CNTRL_OFFSET, FSDIO_CNTRL_INT_ENABLE);

    /* disable generation of Busy Clear Interrupt */
    FSDIO_CLR_BITS(ctrl_p, FSDIO_REG_CARD_THRCTL_OFFSET, FSDIO_CARD_THRCTL_BUSY_CLR);
    

    return FSDIO_SUCCESS;
}